/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.view;

import java.awt.Color;
import java.awt.Font;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

/**
 *
 * @author Walter Lütgenau
 */
public class NodesLookAndFeelManager {
    public static final String LF_NIMBUS = "Nimbus";
    
    static NodesLookAndFeelManager instance = new NodesLookAndFeelManager();

    /**
     * Set the look and feel.
     *
     * Currently, this is nimbus on UNIX, else the system look and feel. If no such l&f is present,
     * use the java l&f.
     *
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws UnsupportedLookAndFeelException
     */
    public static void setLookAndFeel() throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, NoSuchFieldException {
        instance.internalSetLookAndFeel();
    }

    /**
     * Set the look and feel.
     *
     * Currently, this is nimbus on UNIX, else the system look and feel. If no such l&f is present,
     * use the java l&f.
     *
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws UnsupportedLookAndFeelException
     */
    protected void internalSetLookAndFeel() throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException, NoSuchFieldException {
        String lookAndFeel = null;
        boolean isNimbus = false;

        if (useNimbus()) {
            lookAndFeel = getNimbus();
            isNimbus = true;
        }

        if (lookAndFeel == null)
            lookAndFeel = UIManager.getSystemLookAndFeelClassName();

        if (lookAndFeel == null)
            lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();

        UIManager.setLookAndFeel(lookAndFeel);
        
        if (isNimbus)
            configureNimbus();
    }

    /**
     * Return the name of the nimbus look and feel, if present
     *
     * @return
     */
    protected String getNimbus() {
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if (LF_NIMBUS.equals(info.getName()))
                return info.getClassName();
        }

        return null;
    }
    
    /**
     * Override some Nimbus settings.
     * 
     * Unfortunately, Mr. Jasper Potts, whom I would like to praise in other respects, thinks, that
     * a library should have final classes. 
     */
    protected void configureNimbus() throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Color nimbusSelectionBackground = new Color(51,90,157);
        
        UIManager.put("nimbusSelectionBackground", nimbusSelectionBackground);        
        UIManager.put("Tree.rendererFillBackground", new Boolean(true));
        
        Object backgroundPainter = UIManager.get("Tree:TreeCell[Focused+Selected].backgroundPainter");
        Field selectedBackgroundColorField = backgroundPainter.getClass().getDeclaredField("color2");
        selectedBackgroundColorField.setAccessible(true);
        selectedBackgroundColorField.set(backgroundPainter, Color.WHITE);
        Field focusedBackgroundColorField = backgroundPainter.getClass().getDeclaredField("color1");
        focusedBackgroundColorField.setAccessible(true);
        focusedBackgroundColorField.set(backgroundPainter, Color.WHITE);
        
        backgroundPainter = UIManager.get("Tree:TreeCell[Enabled+Selected].backgroundPainter");
        selectedBackgroundColorField = backgroundPainter.getClass().getDeclaredField("color2");
        selectedBackgroundColorField.setAccessible(true);
        selectedBackgroundColorField.set(backgroundPainter, Color.WHITE);
        focusedBackgroundColorField = backgroundPainter.getClass().getDeclaredField("color1");
        focusedBackgroundColorField.setAccessible(true);
        focusedBackgroundColorField.set(backgroundPainter, Color.WHITE);        
        
        Object iconPainter = UIManager.get("Tree[Enabled+Selected].collapsedIconPainter");
        Field enabledColorField = iconPainter.getClass().getDeclaredField("color26");
        enabledColorField.setAccessible(true);
        Color enabledColor = (Color) enabledColorField.get(iconPainter);
        Field selectedColorField = iconPainter.getClass().getDeclaredField("color4");
        selectedColorField.setAccessible(true);
        selectedColorField.set(iconPainter, enabledColor);
        
        iconPainter = UIManager.get("Tree[Enabled+Selected].expandedIconPainter");
        enabledColorField = iconPainter.getClass().getDeclaredField("color26");
        enabledColorField.setAccessible(true);
        enabledColor = (Color) enabledColorField.get(iconPainter);
        selectedColorField = iconPainter.getClass().getDeclaredField("color4");
        selectedColorField.setAccessible(true);
        selectedColorField.set(iconPainter, enabledColor);
        
        Font treeFont = (Font) UIManager.get("Tree.font");
        treeFont = treeFont.deriveFont((float) (treeFont.getSize() - 1));
        UIManager.getLookAndFeelDefaults().put("Tree.font", treeFont);
    }

    /**
     * Is this a UNIX derivative?
     *
     * @return
     */
    protected boolean isUnix() {
        HashSet<String> unixOs = new HashSet<String>(Arrays.asList(new String[] {
            "linux", "solaris", "hp-ux", "aix", "freebsd", "irix", "digitalunix", "osf1"
        }));

        if (unixOs.contains(System.getProperty("os.name").toLowerCase()))
            return true;
        return false;
    }
    
    protected boolean useNimbus() {
        if ("nimbus".equals(System.getProperty("nodes.laf")))
            return true;
        
        if (isUnix())
            return true;
        
        return false;
    }


}
